package com.xiaopeng.common.enumUtil;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.WeakHashMap;

public class EnumViewHandler {

    // EnumView对应的 枚举code->枚举name 映射转换map 缓存
    private static final WeakHashMap<String, Map<Object, String>> enumNameConvertCacheMap = new WeakHashMap<>();

    // EnumView对应的 枚举name->枚举code 映射转换map 缓存
    private static final WeakHashMap<String, Map<String, Object>> enumCodeConvertCacheMap = new WeakHashMap<>();

    private static String getCacheKey(EnumView excelView) {
        return excelView.value().getName() + ":" + excelView.codeField() + ":" + excelView.nameField();
    }


    /**
     * 获取 枚举name 感觉 枚举code
     * @param excelView
     * @param code
     * @return
     */
    public static String getNameByCode(EnumView excelView, Object code) {
        Map<Object, String> enumNameConvertMap = getEnumNameConvertMap(excelView);
        return enumNameConvertMap.getOrDefault(code, String.valueOf(code));
    }

    /**
     * 获取 枚举code->枚举name 映射转换map
     * @param excelView
     * @return
     * @throws Exception
     */
    public static Map<Object, String> getEnumNameConvertMap(EnumView excelView)  {
        String cacheKey = getCacheKey(excelView);
        if (enumNameConvertCacheMap.containsKey(cacheKey)) {
            return enumNameConvertCacheMap.get(cacheKey);
        }
        Map<Object, String> enumConvertMap = generateEnumNameConvertMap(excelView);
        enumNameConvertCacheMap.put(cacheKey, enumConvertMap);
        return enumConvertMap;
    }

    /**
     * 获取 枚举name->枚举code 映射转换map
     * @param excelView
     * @return
     * @throws Exception
     */
    private static Map<Object, String> generateEnumNameConvertMap(EnumView excelView) {
        Class<? extends Enum<?>> enumClass = excelView.value();
        Map<Object, String> result = new HashMap<>();
        Enum<?>[] enumConstants = enumClass.getEnumConstants();
        Field codeField = getField(enumClass, excelView.codeField());
        Field nameField = getField(enumClass, excelView.nameField());
        for (Enum<?> enumItem : enumConstants) {
            Object code = getFileValue(codeField, enumItem);
            String name = String.valueOf(getFileValue(nameField, enumItem));
            if (Objects.nonNull(code) && Objects.nonNull(name)) {
                result.put(code, name);
            }
        }
        return result;
    }


    /**
     * 获取 枚举code 感觉 枚举name
     * @param excelView
     * @param name
     * @return
     */
    public static Object getCodeByName(EnumView excelView, String name) {
        Map<String, Object> enumCodeConvertMap = getEnumCodeConvertMap(excelView);
        return enumCodeConvertMap.get(name);
    }

    /**
     * 获取 枚举name->枚举code 映射转换map
     * @param excelView
     * @return
     * @throws Exception
     */
    public static Map<String, Object> getEnumCodeConvertMap(EnumView excelView) {
        String cacheKey = getCacheKey(excelView);
        if (enumCodeConvertCacheMap.containsKey(cacheKey)) {
            return enumCodeConvertCacheMap.get(cacheKey);
        }
        Map<String, Object> enumConvertMap = generateEnumCodeConvertMap(excelView);
        enumCodeConvertCacheMap.put(cacheKey, enumConvertMap);
        return enumConvertMap;
    }

    /**
     * 获取对应的枚举映射转换map
     * @param excelView
     * @return
     * @throws Exception
     */
    private static Map<String, Object> generateEnumCodeConvertMap(EnumView excelView) {
        Class<? extends Enum<?>> enumClass = excelView.value();
        Map<String, Object> result = new HashMap<>();
        Enum<?>[] enumConstants = enumClass.getEnumConstants();
        Field codeField = getField(enumClass, excelView.codeField());
        Field nameField = getField(enumClass, excelView.nameField());
        for (Enum<?> enumItem : enumConstants) {
            Object code = getFileValue(codeField, enumItem);
            String name = String.valueOf(getFileValue(nameField, enumItem));
            if (Objects.nonNull(code) && Objects.nonNull(name)) {
                result.put(name, code);
            }
        }
        return result;
    }




    /**
     * 获取class字段
     * @param clazz
     * @param fieldName
     * @return
     */
     public static Field getField(Class clazz, String fieldName){
        try {
            Field field =  clazz.getDeclaredField(fieldName);
            // 设置可访问性
            field.setAccessible(true);
            return field;
        } catch (NoSuchFieldException e) {
            throw new RuntimeException(clazz.getName() + "不存在字段" + fieldName);
        }
    }

    /**
     * 获取字段值
     * @param field
     * @param obj
     * @return
     */
    private static Object getFileValue(Field field, Object obj) {
        try {
            return field.get(obj);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

}
